#pragma once
#include <iostream>
#include <memory>
#include <unordered_map>
#include "Epoller.hpp"
#include "Connection.hpp"

using namespace NS_Epoll;
using namespace NS_Connection;

class EpollServer
{
public:
    EpollServer() : _isrunning(false), _epoller(new Epoller()) {}

    void Init()
    {
        _epoller->Create();
    }

    bool ExistConn(int fd)
    {
        for (auto e : _connections)
        {
            if (e.first == fd && e.second != nullptr)
                return true;
        }
        return false;
    }

    void AddConnection(Connection *conn)
    {
        if (conn == nullptr)
            return;
        if (ExistConn(conn->GetSockFd()))
            return;

        _connections[conn->GetSockFd()] = conn;
        _epoller->Add(conn->GetSockFd(), conn->GetEvent());
        LOG(Info, "add connection success, %d\n", conn->GetSockFd());
    }

    void ModConnection(Connection *conn, bool care_read, bool care_write)
    {
        if (conn == nullptr)
            return;
        if (!ExistConn(conn->GetSockFd()))
            return;

        uint32_t event = (care_read ? EPOLLIN : 0) | (care_write ? EPOLLOUT : 0) | EPOLLET;
        _connections[conn->GetSockFd()]->SetEvent(event);
        _epoller->Mod(conn->GetSockFd(), conn->GetEvent());
        LOG(Info, "mod connection success, %d\n", conn->GetSockFd());
    }

    void DelConnection(Connection *conn)
    {
        if (conn == nullptr)
            return;
        if (!ExistConn(conn->GetSockFd()))
            return;

        _connections.erase(conn->GetSockFd());
        _epoller->Del(conn->GetSockFd());
        LOG(Info, "del connection success, %d\n", conn->GetSockFd());
    }

    void LoopOnce()
    {
        auto events_arr = _epoller->GetEventsArr();
        int n = _epoller->Wait();
        for (int i = 0; i < n; i++)
        {
            int fd = events_arr[i].data.fd;
            uint32_t event = events_arr[i].events;

            // 当epoll模型等待事件就绪出现错误时，此时对该文件描述符进行读写就会出现错误，
            // 所以可以将所有的错误都转化为IO错误
            if (event & EPOLLERR || event & EPOLLHUP)
            {
                event |= (EPOLLIN | EPOLLOUT);
            }

            if (ExistConn(fd))
            {
                if (event & EPOLLIN)
                {
                    // 写事件就绪
                    _connections[fd]->_reader(_connections[fd]);
                }
                if (event & EPOLLOUT)
                {
                    // 读事件就绪
                    _connections[fd]->_writer(_connections[fd]);
                }
            }
        }
    }

    void Dispatch()
    {
        _isrunning = true;
        while (_isrunning)
        {
            LoopOnce();
            _epoller->DebugPrint();
        }
        _isrunning = false;
    }

    ~EpollServer() {}

private:
    bool _isrunning;

    // 管理epoll模型
    std::unique_ptr<Epoller> _epoller;
    // 管理连接对象
    std::unordered_map<int, Connection *> _connections;
};